package fem2.material;

import java.util.HashMap;
import java.util.Map;

import fem2.Element;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshPart;
import fem2.Model;
import fem2.Node;
import fem2.Observer;

public class ESfemManager extends HostMaterialModel implements Observer {

	private Model m;
	private Map<Integer, Double> smoothingDomainArea = new HashMap<Integer, Double>();
	private int maxId = 0;

	public ESfemManager(Model m, MaterialModel mm) {
		super(mm);
		int dim = m.getMesh().getDimension();
		assert dim == 2 : "this manager support 2d model only";
		this.m = m;
	}

	/**
	 * get smoothing domain area assciated with edge
	 * 
	 * @param n1
	 * @param n2
	 * @return
	 */
	public double getSmoothingDomainArea(Node n1, Node n2) {
		int min = Math.min(n1.getId(), n2.getId());
		int max = Math.max(n1.getId(), n2.getId());
		int edgeId = min * maxId + max;
		return smoothingDomainArea.get(edgeId);
	}

	@Override
	public void fireStarted() {
		Mesh mesh = m.getMesh();

		/*
		 * get the maximum id of nodes
		 */
		for (int i = 0; i < mesh.countNodes(); i++) {
			if (mesh.getNode(i).getId() > maxId) {
				maxId = mesh.getNode(i).getId();
			}
		}

		/*
		 * loop over all elements, extract smoothing domain area
		 */
		for (int i = 0; i < m.countElements(); i++) {
			Element e = m.getElement(i);
			MeshPart mp = e.getMeshPart();
			Node[] nodes = mp.getNodes();
			double Ac = mp.computeVolume() / nodes.length;

			for (int j = 0; j < nodes.length; j++) {
				Node n1 = nodes[j];
				Node n2;
				if (j == nodes.length - 1) {
					n2 = nodes[0];
				} else {
					n2 = nodes[j + 1];
				}

				int min = Math.min(n1.getId(), n2.getId());
				int max = Math.max(n1.getId(), n2.getId());
				int edgeId = min * maxId + max;

				Double area = smoothingDomainArea.get(edgeId);
				if (area == null) {
					area = Ac;
				} else {
					area += Ac;
				}
				smoothingDomainArea.put(edgeId, area);
			}
		}

	}

	@Override
	public void fireTimeStepStarted() {
	}

	@Override
	public void fireIterationStarted() {
	}

	@Override
	public void fireIterationFinished() {
	}

	@Override
	public void fireTimeStepFinished() {
	}

	@Override
	public void fireFinished() {
	}

}
